package com.naiterui.ehp.bs.esign.api.netrain.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.UUID;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfWriter;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bs.esign.exception.ExceptionCodes;
import com.naiterui.ehp.bs.esign.utils.Constants;

import lombok.extern.slf4j.Slf4j;

/**
 * @author guoyongxiang
 * @date 2020/1/14 15:55
 * @since 1.0.0
 */
@Slf4j
public class NetrainPdfSignUtil {

    /**
     * PDF签名(PDF贴签名图片)
     * 
     * @param sourcePath
     *            源PDF 绝对路径
     * @param targetPath
     *            目标PDF 绝对路径
     * @param sealImagePath
     *            签章图片 绝对路径
     * @param x
     *            签章图定位横坐标
     * @param y
     *            签章图定位纵坐标
     * @return 目标PDF base64
     * @throws BusinessException
     */
    public static String oldPdfSign(String userType, String xingkaiSealImage, String sourcePath, String targetPath,
        String sealImagePath, int x, int y) throws BusinessException {
        if (StringUtils.isBlank(targetPath)) {
            targetPath = "/tmp/" + UUID.randomUUID() + ".pdf";
        }
        File targetFile = new File(targetPath);
        try {
            FileUtils.forceMkdirParent(targetFile);
        } catch (IOException e) {
            log.error("创建PDF签名文件目录失败 targetPath:{}", targetPath, e);
            throw new BusinessException(ExceptionCodes.FAILED, "创建PDF签名文件目录失败");
        }

        // Create output PDF
        Document document = new Document(PageSize.A4);
        PdfWriter writer;
        try {
            FileOutputStream fos = new FileOutputStream(targetPath);
            writer = PdfWriter.getInstance(document, fos);
            document.open();
        } catch (IOException | DocumentException e) {
            log.error("获取签名文件PDF异常 targetPath:{}", targetPath);
            throw new BusinessException(ExceptionCodes.FAILED, "获取签名文件PDF异常");
        }

        PdfContentByte cb = writer.getDirectContent();
        PdfReader reader;
        try (FileInputStream inputStream = new FileInputStream(new File(sourcePath))) {
            reader = new PdfReader(inputStream);

        } catch (IOException e) {
            log.error("读取待签名文件PDF异常 sourcePath:{}", sourcePath);
            throw new BusinessException(ExceptionCodes.FAILED, "读取待签名文件PDF异常");
        }

        PdfImportedPage page = writer.getImportedPage(reader, 1);

        // Copy first page of existing PDF into output PDF
        document.newPage();
        cb.addTemplate(page, 0, 0);

        // Add your new data / text here
        try {
            addImage(document, sealImagePath, x, y, 60, 60);
            if (StringUtils.isNotBlank(xingkaiSealImage)) {
                // 设置行楷签名的位置
                if (Constants.USER_TITLE_DR.equals(userType)) {
                    // 医生
                    log.info("  签名设置医生行楷签名图位置 xingkaiSealImage={}", xingkaiSealImage);
                    addImage(document, xingkaiSealImage, x - 40, y - 5, 40, 40);
                } else if (Constants.USER_TITLE_PH.equals(userType)) {
                    // 药师
                    log.info("  签名设置药师行楷签名图位置 xingkaiSealImage={}", xingkaiSealImage);
                    addImage(document, xingkaiSealImage, x - 40, y - 5, 40, 40);
                } else if (Constants.USER_TITLE_AL_PH.equals(userType)) {
                    // 调配药师
                    log.info("  签名设置调配药师行楷签名图位置 xingkaiSealImage={}", xingkaiSealImage);
                    addImage(document, xingkaiSealImage, x - 40, y - 5, 40, 40);
                }
            }
        } catch (Exception e) {
            log.error("待签文件PDF添加签章图片异常 sourcePath:{}", sourcePath);
            throw new BusinessException(ExceptionCodes.FAILED, "待签处方PDF添加签章图片异常");
        }
        document.close();

        byte[] b;
        try {
            b = Files.readAllBytes(Paths.get(targetPath));
        } catch (IOException e) {
            log.error("已签名文件PDF转换Base64异常 targetPath:{}", targetPath);
            throw new BusinessException(ExceptionCodes.BASE64_ENCODE_ERROR);
        }
        return Base64.getEncoder().encodeToString(b);
    }

    /**
     * PDF签名(PDF贴签名图片)
     *
     * @param sourcePath
     *            源PDF 绝对路径
     * @param targetPath
     *            目标PDF 绝对路径
     * @param sealImagePath
     *            签章图片 绝对路径
     * @param x
     *            签章图定位横坐标
     * @param y
     *            签章图定位纵坐标
     * @return 目标PDF base64
     * @throws BusinessException
     */
    public static String pdfSign(String userType, String xingkaiSealImage, String sourcePath, String targetPath,
        String sealImagePath, int x, int y) throws BusinessException {
        if (StringUtils.isBlank(targetPath)) {
            targetPath = "/tmp/" + UUID.randomUUID() + ".pdf";
        }
        File targetFile = new File(targetPath);
        try {
            FileUtils.forceMkdirParent(targetFile);
            PdfReader reader = new PdfReader(sourcePath);
            PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(targetPath));
            PdfContentByte under = stamper.getOverContent(1);
            underAddImage(under, sealImagePath, x, y, 60, 60);
            if (StringUtils.isNotBlank(xingkaiSealImage)) {
                // 设置行楷签名的位置
                if (Constants.USER_TITLE_DR.equals(userType)) {
                    // 医生
                    log.info("  签名设置医生行楷签名图位置 xingkaiSealImage={}", xingkaiSealImage);
                    underAddImage(under, xingkaiSealImage, x - 40, y - 5, 40, 40);
                } else if (Constants.USER_TITLE_PH.equals(userType)) {
                    // 药师
                    log.info("  签名设置药师行楷签名图位置 xingkaiSealImage={}", xingkaiSealImage);
                    underAddImage(under, xingkaiSealImage, x - 40, y - 5, 40, 40);
                } else if (Constants.USER_TITLE_AL_PH.equals(userType)) {
                    // 调配药师
                    log.info("  签名设置调配药师行楷签名图位置 xingkaiSealImage={}", xingkaiSealImage);
                    underAddImage(under, xingkaiSealImage, x - 40, y - 5, 40, 40);
                }
            }
            stamper.close();
        } catch (Exception e) {
            log.error("创建PDF签名文件目录失败 targetPath:{}", targetPath, e);
            throw new BusinessException(ExceptionCodes.FAILED, "创建PDF签名文件目录失败");
        }
        byte[] b;
        try {
            b = Files.readAllBytes(Paths.get(targetPath));
        } catch (IOException e) {
            log.error("已签名文件PDF转换Base64异常 targetPath:{}", targetPath);
            throw new BusinessException(ExceptionCodes.BASE64_ENCODE_ERROR);
        }
        return Base64.getEncoder().encodeToString(b);
    }

    private static void underAddImage(PdfContentByte under, String sealImagePath, int x, int y, int fitW, int fitH)
        throws IOException, DocumentException {
        File file = new File(sealImagePath);
        if (file.exists()) {
            Image image = Image.getInstance(sealImagePath);
            image.setAbsolutePosition(x, y);
            image.scaleToFit(fitW, fitH);
            under.addImage(image);
        }
    }

    private static void addImage(Document document, String path, int x, int y, int fitW, int fitH)
        throws IOException, DocumentException {
        if (StringUtils.isBlank(path)) {
            return;
        }
        File file = new File(path);
        if (file.exists()) {
            Image image = Image.getInstance(path);
            image.setAbsolutePosition(x, y);
            image.scaleToFit(fitW, fitH);
            document.add(image);
        }
    }

}
